package com.lzp.controller;

import com.lzp.pojo.Users;
import com.lzp.pojo.bo.ShopcartBO;
import com.lzp.pojo.bo.UserBO;
import com.lzp.pojo.vo.UsersVO;
import com.lzp.service.StuService;
import com.lzp.service.TransactionalService;
import com.lzp.service.UserService;
import com.lzp.utils.*;
import com.lzp.utils.error.BusinessException;
import com.lzp.utils.error.ResponseCode;
import com.lzp.utils.error.ServerException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * 注册登录相关接口
 *
 * @author lzp
 * @date 2020/6/27
 */
@Api(value = "注册登录", tags = "注册登录相关接口")
@RestController
@RequestMapping("passport")
public class PassportController extends BaseController {

    @Autowired
    private UserService userService;

    @Autowired
    private RedisOperator redis;

    /**
     * 校验用户名是否存在
     *
     * @param username 用户名
     * @return
     */
    @ApiOperation(value = "用户名是否存在", notes = "用户名是否存在", httpMethod = "GET")
    @GetMapping("/usernameIsExist")
    public ServerResponse usernameIsExist(@RequestParam String username) {

        // 校验用户名不能为空
        if (StringUtils.isBlank(username)) {
            return ServerResponse.createByErrorMsg("用户名不能为空");
        }

        // 校验用户名是否存在
        boolean isExist = userService.queryUsernameIsExist(username);
        if (isExist) {
            return ServerResponse.createByErrorMsg("用户名已存在");
        }

        // 不存在，则可以注册
        return ServerResponse.createBySuccess();
    }

    /**
     * 注册接口
     *
     * @param userBO
     * @return
     * @RequestBody 接收JSON对象
     */
    @ApiOperation(value = "用户注册", notes = "用户注册", httpMethod = "POST")
    @PostMapping("/regist")
    public ServerResponse regist(@RequestBody UserBO userBO,
                                 HttpServletRequest request,
                                 HttpServletResponse response) {

        // 验证前后端都要做
        String username = userBO.getUsername();
        String password = userBO.getPassword();
        String confirmPassword = userBO.getConfirmPassword();

        // 判断用户和密码不为空
        if (StringUtils.isBlank(username)
                || StringUtils.isBlank(password)
                || StringUtils.isBlank(confirmPassword)) {
            return ServerResponse.createByErrorMsg("用户名或密码不能为空");
        }

        // 查询用户名是否存在
        boolean isExist = userService.queryUsernameIsExist(username);
        if (isExist) {
            return ServerResponse.createByErrorMsg("用户名已存在");
        }

        // 判断密码长度不能少于6位
        if (password.length() < 6) {
            return ServerResponse.createByErrorMsg("密码长度不能少于6位");
        }

        // 判断密码是否一致
        if (!password.equals(confirmPassword)) {
            return ServerResponse.createByErrorMsg("两次密码输入不一致");
        }

        // 注册
        Users user = userService.createUser(userBO);

        // 敏感信息置空
        // result = setNullProperty(result);
        // 实现用户的Redis会话
        UsersVO usersVO = convertUsersVO(user);

        CookieUtils.setCookie(request, response, PASSPORT_COOKIE,
                JsonUtils.objectToJson(usersVO), true);

        // 同步购物车数据
        synchShopcartData(user.getId(), request, response);
        return ServerResponse.createBySuccess("注册成功", usersVO);
    }


    /**
     * 注册/登录成功后，同步Cookie和redis中的购物车数据
     */
    private void synchShopcartData(String userId,
                                   HttpServletRequest request,
                                   HttpServletResponse response) {
        /**
         * 1. redis中无数据
         * 1.1 如果cookie的购物车数据为空，不做处理
         * 1.2 如果cookie数据不为空，则直接放入redis中
         * 2. redis有数据
         * 2.1 若cookie数据为空，则redis数据覆盖本地cookie
         * 2.2 若cookie数据不为空，则以cookie中数据为主，覆盖删除redis中数据。
         * 京东的思想如上，淘宝则必须要登录才能加购物车
         * 3. 覆盖更新本地cookie数据
         */
        String redisKey = "foodie:shopcart:" + userId;
        String shopCartRedis = redis.get(redisKey);
        String shopCartCookie = CookieUtils.getCookieValue(request, SHOPCART_COOKIE, true);
        if (StringUtils.isBlank(shopCartRedis)) {
            if (StringUtils.isNotBlank(shopCartCookie)) {
                // redis无数据，cookie有数据
                redis.set(redisKey, shopCartCookie);
            }
        } else {
            if (StringUtils.isNotBlank(shopCartCookie)) {
                // redis有数据，cookie有数据
                List<ShopcartBO> redisShopcartList = JsonUtils.jsonToList(shopCartRedis, ShopcartBO.class);
                List<ShopcartBO> cookieShopcartList = JsonUtils.jsonToList(shopCartCookie, ShopcartBO.class);
                // 待删除List
                List<ShopcartBO> pendingDeleteList = new ArrayList<>();
                for (ShopcartBO redisShopcart : redisShopcartList) {
                    String redisSpecId = redisShopcart.getSpecId();
                    for (ShopcartBO cookieShopcart : cookieShopcartList) {
                        String cookieSpecId = cookieShopcart.getSpecId();
                        if (redisSpecId.equals(cookieSpecId)) {
                            // cookie购买数据覆盖redis数量
                            redisShopcart.setBuyCounts(cookieShopcart.getBuyCounts());
                            // 更新待删除列表
                            pendingDeleteList.add(cookieShopcart);
                        }
                    }
                }
                // cookie删除待删除商品数据
                cookieShopcartList.removeAll(pendingDeleteList);
                // 合并数据
                redisShopcartList.addAll(cookieShopcartList);
                // 更新redis和cookie
                CookieUtils.setCookie(request, response, SHOPCART_COOKIE, JsonUtils.objectToJson(redisShopcartList), true);
                redis.set(redisKey, JsonUtils.objectToJson(redisShopcartList));
            } else {
                // redis有数据，cookie无数据
                CookieUtils.setCookie(request, response, SHOPCART_COOKIE, shopCartRedis, true);
            }
        }
    }

    /**
     * 登录接口
     * <p>
     * 以京东为例，京东是将登录后用户数据加密存放在cookie中的。
     *
     * @param userBO 请求数据
     * @return
     */
    @ApiOperation(value = "用户登录", notes = "用户登录", httpMethod = "POST")
    @PostMapping("/login")
    public ServerResponse login(@RequestBody UserBO userBO,
                                HttpServletRequest request,
                                HttpServletResponse response) throws Exception {

        String username = userBO.getUsername();
        String password = userBO.getPassword();

        // 判断用户和密码不为空
        if (StringUtils.isBlank(username)
                || StringUtils.isBlank(password)) {
            return ServerResponse.createByErrorMsg("用户名或密码不能为空");
        }

        // 登录校验
        Users user = userService.queryUserForLogin(username, MD5Utils.getMD5Str(password));
        if (user == null) {
            return ServerResponse.createByErrorMsg("用户名或密码不正确");
        }

        // 敏感信息置空
        // result = setNullProperty(result);
        UsersVO usersVO = convertUsersVO(user);

        // 设置cookie，并加密
        CookieUtils.setCookie(request, response, PASSPORT_COOKIE,
                JsonUtils.objectToJson(usersVO), true);

        // 同步cookie和redis购物车数据
        synchShopcartData(user.getId(), request, response);

        return ServerResponse.createBySuccess(usersVO);
    }

    private Users setNullProperty(Users result) {
        result.setPassword(null);
        result.setMobile(null);
        result.setEmail(null);
        result.setCreatedTime(null);
        result.setUpdatedTime(null);
        result.setBirthday(null);
        return result;
    }

    /**
     * 用户退出登录
     */
    @ApiOperation(value = "退出登录", notes = "退出登录", httpMethod = "POST")
    @PostMapping("/logout")
    public ServerResponse logout(@RequestParam String userId,
                                 HttpServletRequest request,
                                 HttpServletResponse response) {

        // 清除浏览器本地Cookie
        CookieUtils.deleteCookie(request, response, PASSPORT_COOKIE);
        // 退出登录，清空本地购物车cookie
        CookieUtils.deleteCookie(request, response, SHOPCART_COOKIE);
        // 分布式会话中清除用户数据
        redis.del(REDIS_USER_TOKEN + ":" + userId);

        return ServerResponse.createBySuccessMsg("退出登录");
    }

}
